using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using UnityEngine;
using UnityEngine.Playables;

namespace IQIGame.Onigao.GamePlay
{
    public class UnitEffectBehaviour : PlayableBehaviour
    {
        public string effectName;
        public string effectPath;
        public int selfDummy;
        public bool loop;
        public EVFXSpace followType;
        public Vector3 shifting;

        // Laser
        public float defaultLength;

        private Transform rootPoint;
        private double startTime = -1;
        private EffectComponent effectComp;

        private TimelineAssetInfo _timelineAssetInfo;
        private TimelineAssetInfo.TimelineEffect _effectAsset;
        private Effect _effect;
        private bool _loadingEffect;

        public static ScriptPlayable<UnitEffectBehaviour> Create(PlayableGraph graph, GameObject gameObject)
        {
            if (gameObject == null)
                return ScriptPlayable<UnitEffectBehaviour>.Null;

            var handle = ScriptPlayable<UnitEffectBehaviour>.Create(graph);
            var playable = handle.GetBehaviour();
            var rBindRef = graph.GetResolver().GetReferenceValue(TimelineAssetInfo.RefInfoID, out var idValid);
            if (idValid)
            {
                playable._timelineAssetInfo = (rBindRef as TimelineAssetInfoHandler).assetInfo;
            }
            return handle;
        }

        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
#if UNITY_EDITOR
            if (playerData == null && !Application.isPlaying)
            {
                LogGame.LogError("Editor下必须使用对应编辑器启动此Timeline");
                return;
            }
#endif
            if (!this.rootPoint)
            {
                var rEntityDriver = playerData as EntityDriver;
                this.rootPoint = rEntityDriver.transform;
                // 以下部分留着为了兼容战斗中的特效轨道仅配置了name需要实时获取路径的问题
                var rUnitView = BattleClientUtil.GetUnitViewByEntityDriver(rEntityDriver);
                if (rUnitView != null)
                {
                    this.effectComp = rUnitView.GetComponent<EffectComponent>(ETComponentType.EffectComponent);

                    // playable._timelineAssetInfo = playable.timelineComp.curTimeline.asset;
                }
            }

#if UNITY_EDITOR
            if (this.effectGo != null && !BattleClientUtil.IsEditorMode && !StoryClientUtil.IsEditorMode)
            {
                OnPreviewProcessFrame(playable, info);
                return;
            }
#endif

            if (playable.GetDuration() - playable.GetTime() < 0.01f)
            {
                this.StopEffect();
            }
            else if (this.startTime >= 0)
            {
                if (this._effect == null)
                {
                    this.AddEffect();
                }
                else
                {
                    var fCurTime = playable.GetPreviousTime();
                    this._effect.Simulate(fCurTime);
                }
            }
        }

        public override void OnBehaviourPlay(Playable playable, FrameData info)
        {
            this.startTime = playable.GetTime();
            if (this.effectComp == null || this._effect != null)
            {
                return;
            }
            this.AddEffect();
        }

        public override void OnBehaviourPause(Playable playable, FrameData info)
        {
            base.OnBehaviourPause(playable, info);
            this.StopEffect();
        }

        private void StopEffect()
        {
            if (this._effect != null)
            {
                if (this._effectAsset != null)
                {
                    this._timelineAssetInfo.FreeEffect(this._effectAsset);
                }
#if UNITY_EDITOR
                if (this.effectGo)
                {
                    this.effectGo.SetActive(false);
                }
#endif
                this._effect.FreeController();
                ClassPool.Put(this._effect);
                this._effect = null;
            }
        }

        private void AddEffect()
        {
            if (this._effect == null && !this._loadingEffect)
            {
                this.CreateEffect().Forget();
            }
        }

        private async UniTaskVoid CreateEffect()
        {
            this._loadingEffect = true;
            Transform rDummyTrans = null;
            if (this.selfDummy == 0)
            {
                rDummyTrans = this.rootPoint.transform.Find("model/Root");
            }
            else if (this.selfDummy == -1)
            {
                // 相机点
#if UNITY_EDITOR
                if (BattleClientUtil.IsEditorMode || StoryClientUtil.IsEditorMode)
                {
                    rDummyTrans = Camera.main.transform;
                }
                else
#endif
                {
                    rDummyTrans = ManagerCenter.UI.MainCamera.transform;
                }
            }
            else
            {
#if UNITY_EDITOR
                if (TableCenter.entityBindPoint == null)
                {
                }
                else
#endif
                {
                    rDummyTrans = BindPointUtil.GetBindPoint(this.selfDummy, this.rootPoint);
                }
            }
            var rTargetPos = this.rootPoint.position;
            // 激光的默认长度
            if (this.defaultLength > 0)
            {
                var rForward = this.rootPoint.forward;
                rTargetPos = this.rootPoint.position + rForward * this.defaultLength;
            }
            var rInitParam = new EffectInitParam(effectPath, rDummyTrans, shifting, Quaternion.identity, rTargetPos, null,
                1, false, EVFXSpace.Local, null, false);
            var rEffect = ClassPool<Effect>.Get();

            Transform rEffectTrans;
#if UNITY_EDITOR
            if (this.effectGo)
            {
                rEffectTrans = this.effectGo.transform;
                this.effectGo.SetActive(true);
            }
            else
#endif
            {
                // 这里是对旧资源的兼容
                if (string.IsNullOrEmpty(this.effectPath) && this.effectComp != null && !string.IsNullOrEmpty(this.effectName))
                {
                    this.effectPath = this.effectComp.GetRoleEffectPath(this.effectName);
                }

                if (string.IsNullOrEmpty(this.effectPath))
                {
                    return;
                }
                this._effectAsset = await this._timelineAssetInfo.FetchEffect(this.effectPath);
                rEffectTrans = this._effectAsset.gameObject.transform;
            }
            rEffect.SetPlayParam(rEffectTrans, rInitParam);
            rEffect.Play(rInitParam);
            this._effect = rEffect;
            this._loadingEffect = false;
        }

#if UNITY_EDITOR

        GameObject effectGo;
        ParticleSystem emitRoot;

        public void SetPreviewGo(GameObject go)
        {
            this.effectGo = go;
        }

        void OnPreviewProcessFrame(Playable playable, FrameData info)
        {
            if (emitRoot == null)
                emitRoot = this.effectGo.GetComponentInChildren<ParticleSystem>();
            if (emitRoot == null) return;

            var time = (float)playable.GetPreviousTime();
            emitRoot.Simulate((float)time, true, true);
        }
#endif
    }
}